﻿
//编译器类--把源程序编译为汇编程序
namespace n_MCS51_Assembler
{
using System;
using n_ASMLabel;
using n_Compiler;
using n_EQU;
using n_ET;
using n_HEXToDEC;
using n_Number;
using i_Compiler;
using n_OS;

public static class MCS51_Assembler
{
	//编译器启动初始化,加载汇编运算库文件
	public static void LoadFile()
	{
		ASMLabel.Init();
		
		//加载运算信息表
		string s = i_Compiler.Compiler.OpenCompileFile( n_Config.Config.Path_compiler + "CPU" + OS.PATH_S + "MCS51" + OS.PATH_S + "hexcode.lst" );
		s = s.Remove( s.IndexOf( "\n<end>" ) );
		string[] Lines = s.Split( '\n' );
		HEXList = new string[ Lines.Length ][];
		for( int i = 0; i < Lines.Length; ++i ) {
			HEXList[ i ] = Lines[ i ].Remove( Lines[ i ].IndexOf( "<<<<" ) ).Split( '\\' );
		}
	}
	
	//编译汇编文件
	public static string Assemble( string Source )
	{
		//初始化汇编器
		n_Compiler.Compiler.CompilingStep( n_Compiler.Compiler.STEP_InitAssemble );
		
		//清除错误列表
		ET.Clear();
		//初始化自定义符号表
		EQU.Reset();
		//初始化标号列表
		ASMLabel.Clear();
		
		n_Compiler.Compiler.CompilingStep( n_Compiler.Compiler.STEP_Assemble );
		
		//转换顺序指令
		Source = SwitchDirect( Source );
		
		//定位绝对地址
		Source = AddAddress( Source );
		
		//定位相对地址
		Source = SwitchOffsetAddress( Source );
		
		//转换为机器代码记录
		Source = SwitchRecord( Source );
		
		return Source;
	}
	
	//检查汇编文件
	public static void Check( string Source )
	{
		//清除错误列表
		ET.Clear();
		//初始化自定义符号表
		EQU.Reset();
		//初始化标号列表
		ASMLabel.Clear();
		
		//转换顺序指令
		Source = SwitchDirect( Source );
		//定位绝对地址
		Source = AddAddress( Source );
		//定位相对地址
		Source = SwitchOffsetAddress( Source );
		//转换为机器代码记录
		Source = SwitchRecord( Source );
	}
	
	//转换为机器代码记录
	static string SwitchRecord( string Source )
	{
		string Cut = string.Join( "", Source.Trim( '\n' ).Split( '\n' ) );
		string result = "";
		string Current = "";
		int StartAddr = 0;
		for( int i = 0; i < Cut.Length; ++i ) {
			Current += Cut[ i ].ToString();
			if( i == Cut.Length - 1 || i % 32 == 31 ) {
				string Check = Number.GetByteValue( ( Current.Length / 2 ).ToString(), 0 )
					+ Number.GetDoubleValue( ( StartAddr ).ToString(), 0 ) + "00" + Current;
				result += ":" + Check + GetCheckSum( Check ) + "\n";
				Current = "";
				StartAddr = ( i + 1 ) / 2;
			}
		}
		result += ":00000001FF\n";
		return result;
	}
	
	//计算校验和
	static string GetCheckSum( string number )
	{
		int Sum = 0;
		for( int i = 0; i < number.Length; i += 2 ) {
			Sum += HEXToDEC.GetDecValue( number[ i ].ToString() + number[ i + 1 ].ToString() );
			Sum = Sum % 256;
		}
		Sum = 256 - Sum;
		if( Sum == 256 ) {
			Sum = 0;
		}
		return Number.GetByteValue( Sum.ToString(), 0 );
	}
	
	//定位相对地址
	static string SwitchOffsetAddress( string Source )
	{
		string result = "";
		string[] LineCut = Source.Trim( '\n' ).Split( '\n' );
		for( int Line = 0; Line < LineCut.Length; ++Line ) {
			
			if( LineCut[ Line ] == "" ) {
				continue;
			}
			
			string[] Sence = LineCut[ Line ].Split( ' ' );
			int CurrentLine = int.Parse( Sence[ 0 ] );
			int Addr = int.Parse( Sence[ 1 ] );
			if( Addr > 65535 ) {
				ET.WriteLineError( 0, CurrentLine, "机器码超出64K" );
				return "";
			}
			if( Sence[ 2 ].IndexOf( "$" ) == -1 ) {
				result += Sence[ 2 ] + "\n";
				continue;
			}
			string Hex = Sence[ 2 ].Split( '$' )[ 0 ];
			string Ident = Sence[ 2 ].Split( '$' )[ 1 ];
			int Address = ASMLabel.GetValue( Ident );
			if( Address == -1 ) {
				ET.WriteLineError( 0, CurrentLine, "未定义的标号: " + Ident );
				continue;
			}
			if( Hex == "02" || Hex == "12" || Hex == "90" ) {
				result += Hex + Number.GetDoubleValue( Address.ToString(), CurrentLine ) + "\n";
				continue;
			}
			string Offset = GetOffsetAddress( Addr, Address, Hex.Length / 2 + 1, CurrentLine );
			result += Hex + Offset + "\n";
		}
		return result;
	}
	
	//计算相对地址
	static string GetOffsetAddress( int CurrentAddr, int TargetAddr, int OperLength, int Line )
	{
		int Offset = TargetAddr - CurrentAddr - OperLength;
		if( Offset < -128 || Offset > 127 ) {
			ET.WriteLineError( 0, Line, "跳转范围过大: " + Offset );
			return "";
		}
		if( Offset < 0 ) {
			Offset = 256 + Offset;
		}
		return Number.GetByteValue( Offset.ToString(), Line );
	}
	
	//定位绝对地址
	static string AddAddress( string Source )
	{
		string result = "";
		int Address = 0;
		string[] Line = Source.Trim( '\n' ).Split( '\n' );
		for( int i = 0; i < Line.Length; ++i ) {
			string[] Sence = Line[ i ].Split( '\t' );
			int CurrentLine = int.Parse( Sence[ 0 ] );
			if( Sence[ 1 ].EndsWith( @":\" ) ) {
				string Name = Sence[ 1 ].Remove( Sence[ 1 ].Length - 2 );
				if( ASMLabel.GetValue( Name ) != -1 ) {
					ET.WriteLineError( 0, CurrentLine, "已经定义的标号: " + Name );
					continue;
				}
				if( !isIdentifier( Name ) ) {
					ET.WriteLineError( 0, CurrentLine, "标号中有非法字符: " + Name );
					continue;
				}
				ASMLabel.AddNode( Name, Address.ToString() );
				continue;
			}
			if( Sence[ 1 ].StartsWith( @"org *d\" ) ) {
				int NewAddress = HEXToDEC.GetDecValue( Sence[ 1 ].Split( '\\' )[ 1 ] );
				if( NewAddress < Address ) {
					ET.WriteLineError( 0, CurrentLine, "org指令指定的地址无效: " + NewAddress );
					continue;
				}
				while( Address < NewAddress ) {
					result += CurrentLine + " " + Address + " FF\n";
					++Address;
				}
				continue;
			}
			if( Sence[ 1 ].IndexOf( "\\" ) != -1 ) {
				ET.WriteLineError( 0, CurrentLine, "未知的指令: " + Sence[ 1 ] );
				continue;
			}
			if( Sence[ 1 ].IndexOf( "$" ) != -1 ) {
				if( Sence[ 1 ].StartsWith( "02$" ) || Sence[ 1 ].StartsWith( "12$" ) || Sence[ 1 ].StartsWith( "90$" ) ) {
					result += CurrentLine + " " + Address + " " + Sence[ 1 ] + "\n";
					Address += 3;
					continue;
				}
				result += CurrentLine + " " + Address + " " + Sence[ 1 ] + "\n";
				Address += Sence[ 1 ].Split( '$' )[ 0 ].Length / 2 + 1;
				continue;
			}
			result += CurrentLine + " " + Address + " " + Sence[ 1 ] + "\n";
			Address += Sence[ 1 ].Length / 2;
		}
		return result;
	}
	
	//转换顺序指令
	static string SwitchDirect( string Source )
	{
		string Result = "";
		Source = Source.Replace( ",", " , " );
		Source = Source.Replace( "/", " / " );
		Source = Source.Replace( "\t", " " );
		Source =Source.ToLower();
		string[] Cut = Source.Trim( '\n' ).Split( '\n' );
		for( int Line = 0; Line < Cut.Length; ++Line ) {
			CLine = Line;
			string LineASM = Cut[ Line ];
			int Index = LineASM.IndexOf( ";" );
			if( Index != -1 ) {
				LineASM = LineASM.Remove( Index );
			}
			if( LineASM == "" ) {
				continue;
			}
			if( LineASM.IndexOf( ":" ) != -1 && !LineASM.TrimEnd( ' ' ).EndsWith( ":" ) ) {
				int index = LineASM.LastIndexOf( ":" );
				Result += Line.ToString() + "\t" + LineASM.Remove( index ) + @":\" + "\n";
				LineASM = LineASM.Remove( 0, index + 1 );
			}
			LineASM = TurnLine( LineASM );
			if( LineASM == "" ) {
				continue;
			}
			LineASM = SearchHEXList( LineASM );
			if( LineASM == "" ) {
				continue;
			}
			Result += Line.ToString() + "\t" + LineASM + "\n";
		}
		return Result;
	}
	
	//转换一行汇编指令
	static string TurnLine( string Source )
	{
		string[] Cut = Source.Split( ' ' );
		int Length = 0;
		for( int i = 0; i < Cut.Length; ++i ) {
			if( Cut[ i ] != "" ) {
				Cut[ Length ] = Cut[ i ];
				++Length;
			}
		}
		if( Length == 0 ) {
			return "";
		}
		//格式化
		string[] NewCut = new string[ Length ];
		for( int i = 0; i < Length; ++i ) {
			NewCut[ i ] = Cut[ i ];
		}
		//判断定义
		if( NewCut.Length == 3 && NewCut[ 1 ] == "equ" ) {
			if( EQU.GetValue( NewCut[ 0 ] ) != null ) {
				ET.WriteLineError( 0, CLine, "符号已经定义: " + NewCut[ 0 ] );
				return "";
			}
//			if( ASMKeyWord.isKeyWord( NewCut[ 0 ] ) ) {
//				ET.WriteLineError( CLine, "符号与关键字重名: " + NewCut[ 0 ] );
//				return "";
//			}
			EQU.AddNode( NewCut[ 0 ], NewCut[ 2 ] );
			return "";
		}
		//替换EQU的定义符号
		bool noReplace = false;
		while( !noReplace ) {
			noReplace = true;
			for( int i = 0; i < NewCut.Length; ++i ) {
				string r = EQU.GetValue( NewCut[ i ] );
				if( r != null ) {
			  	 	NewCut[ i ] = r;
			  	 	noReplace = false;
				}
			}
		}
		//判断是否定义字节表格
		if( NewCut[ 0 ] == "db" ) {
			string r = "*db ";
			for( int i = 1; i < NewCut.Length; i += 2 ) {
				if( i != 1 && NewCut[ i - 1 ] != "," ) {
					ET.WriteLineError( 0, CLine, "db指令的格式不对: " + Source );
					return "";
				}
				r += Number.GetByteValue( NewCut[ i ], CLine );
			}
			return r;
		}
		//判断是否定义双字节表格
		if( NewCut[ 0 ] == "dw" ) {
			string r = "*dw ";
			for( int i = 1; i < NewCut.Length; i += 2 ) {
				if( i != 1 && NewCut[ i - 1 ] != "," ) {
					ET.WriteLineError( 0, CLine, "dw指令的格式不对: " + Source );
					return "";
				}
				r += Number.GetDoubleValue( NewCut[ i ], CLine );
			}
			return r;
		}
		//分析指令
		string Var = "";
		for( int i = 0; i < NewCut.Length; ++i ) {
			if( NewCut[ i ] == "r0"
				|| NewCut[ i ] == "r1"
				|| NewCut[ i ] == "r2"
				|| NewCut[ i ] == "r3"
				|| NewCut[ i ] == "r4"
				|| NewCut[ i ] == "r5"
				|| NewCut[ i ] == "r6"
				|| NewCut[ i ] == "r7" ) {
				Var += GetRnCode( NewCut[ i ] ) + " ";
				NewCut[ i ] = "*rn";
				continue;
			}
			if( NewCut[ i ] == "@r0" || NewCut[ i ] == "@r1" ) {
				if( NewCut[ 0 ] == "movx" ) {
					if( NewCut[ i ] == "@r0" ) {
						Var += "2 ";
					}
					else {
						Var += "3 ";
					}
				}
				else {
					if( NewCut[ i ] == "@r0" ) {
						Var += "6 ";
					}
					else {
						Var += "7 ";
					}
				}
				NewCut[ i ] = "*@ri";
				continue;
			}
			if( StartsWithDigital( NewCut[ i ] ) ) {
				if( NewCut[ 0 ] == "ljmp" && NewCut.Length == 2 
					|| NewCut[ 0 ] == "lcall" && NewCut.Length == 2
					|| NewCut[ 0 ] == "org" && NewCut.Length == 2 ) {
					Var += Number.GetDoubleValue( NewCut[ i ], CLine ) + " ";
				}
				else {
					Var += Number.GetByteValue( NewCut[ i ], CLine ) + " ";
				}
				NewCut[ i ] = "*d";
				continue;
			}
			string number = NewCut[ i ];
			if( number.StartsWith( "#" ) && StartsWithDigital( number.Remove( 0, 1 ) ) ) {
				number = number.Remove( 0, 1 );
				if( NewCut[ 0 ] == "mov" && NewCut.Length == 4 && NewCut[ 1 ] == "dptr" ) {
					Var += Number.GetDoubleValue( number, CLine ) + " ";
				}
				else {
					Var += Number.GetByteValue( number, CLine ) + " ";
				}
				NewCut[ i ] = "*n";
				continue;
			}
		}
		if( NewCut.Length == 2 && !NewCut[ 1 ].StartsWith( "*" ) && (
			NewCut[ 0 ] == "ljmp" || NewCut[ 0 ] == "lcall" || NewCut[ 0 ] == "sjmp" || 
			NewCut[ 0 ] == "jz" || NewCut[ 0 ] == "jnz" ||
			NewCut[ 0 ] == "jc" || NewCut[ 0 ] == "jnc" ) ) {
			Var += "$" + NewCut[ 1 ];
			NewCut[ 1 ] = "*d";
		}
		if( NewCut.Length == 4 && !NewCut[ 3 ].StartsWith( "*" ) && 
		   NewCut[ 0 ] == "mov" && NewCut[ 1 ] == "dptr" && NewCut[ 2 ] == "," && NewCut[ 3 ].StartsWith( "#" ) ) {
			Var += "$" + NewCut[ 3 ].Remove( 0, 1 );
			NewCut[ 3 ] = "*n";
		}
		if( NewCut.Length == 4 && !NewCut[ 3 ].StartsWith( "*" ) && (
			NewCut[ 0 ] == "jb" || NewCut[ 0 ] == "jnb" || NewCut[ 0 ] == "jbc" || NewCut[ 0 ] == "djnz" ) ) {
			Var += "$" + NewCut[ 3 ];
			NewCut[ 3 ] = "*d";
		}
		if( NewCut.Length == 6 && !NewCut[ 5 ].StartsWith( "*" ) && NewCut[ 0 ] == "cjne" ) {
			Var += "$" + NewCut[ 5 ];
			NewCut[ 5 ] = "*d";
		}
		return string.Join( " ", NewCut ) + @"\" + Var.Trim( ' ' );
	}
	
	//搜索机器码列表
	static string SearchHEXList( string Source )
	{
		if( Source.StartsWith( "*db " ) || Source.StartsWith( "*dw " ) ) {
			return Source.Split( ' ' )[ 1 ];
		}
		string[] Cut = Source.Split( '\\' );
		for( int i = 0; i < HEXList.Length; ++i ) {
			if( Cut[ 0 ] != HEXList[ i ][ 0 ] ) {
				continue;
			}
			string[] Current = Cut[ 1 ].Split( ' ' );
			string[] Lib = HEXList[ i ][ 1 ].Split( ' ' );
			string result = HEXList[ i ][ 2 ];
			if( Current.Length != Lib.Length ) {
				ET.ShowError( "系统错误: 机器码替换值列表的长度不等" );
				return "";
			}
			if( Current.Length == 1 && Current[ 0 ] == "" && Lib[ 0 ] == "" ) {
				return result;
			}
			for( int j = 0; j < Lib.Length; ++j ) {
				result = result.Replace( Lib[ j ], Current[ j ] );
			}
			return result;
		}
		return Source;
	}
	
	//获取r0 - r7 的代码
	static string GetRnCode( string Rn )
	{
		switch( Rn ) {
			case "r0": return "8";
			case "r1": return "9";
			case "r2": return "A";
			case "r3": return "B";
			case "r4": return "C";
			case "r5": return "D";
			case "r6": return "E";
			case "r7": return "F";
			default: ET.ShowError( "系统错误: 未知的寄存器号: " + Rn ); return "0";
		}
	}
	
	//判断一个词是否为标识符 0-9 a-z A-Z _
	static bool isIdentifier( string Name )
	{
		if( Name.Length == 0 || !isLetter( Name[ 0 ] ) ) {
			return false;
		}
		for( int i = 1; i < Name.Length; ++i ) {
			if( !isChar( Name[ i ] ) ) {
				return false;
			}
		}
//		if( CKeyWord.isKeyWord( Name ) ) {
//			return false;
//		}
		return true;
	}
	
	//是否为字母 a-z A-Z _ 中文
	static bool isLetter( char c )
	{
		if( ( c >= 'a' && c <= 'z' ) || ( c >= 'A' && c <= 'Z' ) || c == '_' || c > 127 ) {
			return true;
		}
		return false;
	}
	
	//是否为字符  a-z A-Z _ 中文 0-9
	static bool isChar( char c )
	{
		if( isLetter( c ) || ( c >= '0' && c <= '9' ) ) {
			return true;
		}
		return false;
	}
	
	static bool StartsWithDigital( string Name )
	{
		if( Name.Length > 0 && Name[ 0 ] >= '0' && Name[ 0 ] <= '9' ) {
			return true;
		}
		return false;
	}
	
	static string[][] HEXList;	//机器码列表
	static int CLine;
}
}

